#include "writer.h"
#include "graph.h"
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <ostream>
#include <string>

using namespace std;

Writer::Writer(const Graph &M) {
    if (M.output_type == "file") {
        string fileName = "./data/";
        fileName.append(M.network);
        fileName.append("-");
        fileName.append(M.dynamic);
        for (const auto &item : M.attr) {
            fileName.append("-");
            fileName.append(item.first);
            fileName.append(to_string(item.second).erase(5));
        }
        fileName.append(".csv");
        dataFile.open(fileName);
        if (!dataFile.is_open() && M.output_type == "file") {
            cerr << "ERRORF!" << endl;
            exit(EXIT_FAILURE);
        }
        this->file = fileName;
    }
}

void Writer::writeMetaData(const Graph &M) {
    if (M.output_type == "file") {
        if (!dataFile.is_open()) {
            cerr << "ERRORF!" << endl;
            exit(EXIT_FAILURE);
        }
        dataFile << "network" << ',' << M.network << endl;
        dataFile << "dynamic" << ',' << M.dynamic << endl;
        dataFile << "graph attribute:" << endl;
        for (const auto &item : M.attr)
            dataFile << item.first << ',' << item.second << endl;
        dataFile << "node attribute:" << endl;
        for (const auto &item : M.V[0].furAttr)
            dataFile << item.first << endl;
        dataFile << "edge set:" << ',';
        int sum = 0;
        for (const auto &i : M.E)
            for (const auto &j : i)
                if (j.isConnected)
                    ++sum;
        dataFile << sum / 2;
        dataFile << endl;

        if (M.info_level_meta == "normal" || M.info_level_meta == "all") {
            for (const auto &item : M.E[0])
                dataFile << ',' << item.ID.second;
            dataFile << endl;
            for (const auto &item : M.E) {
                dataFile << item[0].ID.first << ',';
                for (const auto &p : item)
                    dataFile << p.isConnected << ',';
                dataFile << endl;
            }
            dataFile << endl;
        }

        if (M.info_level_meta == "degree" || M.info_level_meta == "all") {
            for (const auto &edge : M.E) {
                int temp_sum = 0;
                for (const auto &neighbor : edge)
                    if (neighbor.isConnected)
                        ++temp_sum;
                dataFile << edge[0].ID.first << ',' << temp_sum << endl;
            }
            dataFile << endl;
        }
    } else if (M.output_type == "terminal") {
        cout << "network" << ',' << M.network << endl;
        cout << "dynamic" << ',' << M.dynamic << endl;
        cout << "graph attribute:" << endl;
        for (const auto &item : M.attr)
            cout << item.first << ',' << item.second << endl;
        cout << "node attribute:" << endl;
        for (const auto &item : M.V[0].furAttr)
            cout << item.first << endl;
        cout << "edge set:" << ',';
        int sum = 0;
        for (const auto &i : M.E)
            for (const auto &j : i)
                if (j.isConnected)
                    ++sum;
        cout << sum / 2;
        cout << endl;

        if (M.info_level_meta == "normal" || M.info_level_meta == "all") {
            for (const auto &item : M.E[0])
                cout << ',' << item.ID.second;
            cout << endl;
            for (const auto &item : M.E) {
                cout << item[0].ID.first << ',';
                for (const auto &p : item)
                    cout << p.isConnected << ',';
                cout << endl;
            }
            cout << endl;
        }

        if (M.info_level_meta == "degree" || M.info_level_meta == "all") {
            for (const auto &edge : M.E) {
                int tempSum = 0;
                for (const auto &neighbor : edge)
                    if (neighbor.isConnected)
                        ++tempSum;
                cout << edge[0].ID.first << ',' << tempSum << endl;
            }
            cout << endl;
        }
    }
}

void Writer::writeTempData(const Graph &M) {
    if (M.info_level_temp == "none")
        exit(EXIT_SUCCESS);

    if (M.output_type == "file") {
        if (!dataFile.is_open()) {
            cerr << "ERRORF!" << endl;
            exit(EXIT_FAILURE);
        }

        dataFile << "date" << M.date;
        for (const auto &item : M.V[0].curAttr)
            dataFile << ',' << item.first;
        auto sum = M.V[0].curAttr;
        for (auto &key : sum)
            key.second = 0;
        for (auto &key : sum) {
            for (const auto &item : M.V) {
                auto p = item.curAttr.find(key.first);
                assert(p != item.curAttr.end());
                key.second += p->second;
            }
        }
        for (const auto &key : sum) {
            dataFile << ',' << "sum of " << key.first << ',' << key.second;
        }
        dataFile << endl;

        if (M.info_level_temp == "all") {
            for (const auto &item : M.V) {
                dataFile << item.ID;
                for (const auto &p : item.curAttr) {
                    dataFile << ',' << p.second;
                }
                dataFile << endl;
            }
            dataFile << endl;
        }

    } else if (M.output_type == "terminal") {

        cout << "date" << M.date;
        for (const auto &item : M.V[0].curAttr)
            cout << ',' << item.first;
        auto sum = M.V[0].curAttr;
        for (auto &key : sum)
            key.second = 0;
        for (auto &key : sum) {
            for (const auto &item : M.V) {
                auto p = item.curAttr.find(key.first);
                assert(p != item.curAttr.end());
                key.second += p->second;
            }
        }
        for (const auto &key : sum) {
            cout << ',' << "sum of " << key.first << ',' << key.second;
        }
        cout << endl;

        if (M.info_level_temp == "all") {
            for (const auto &item : M.V) {
                cout << item.ID;
                for (const auto &p : item.curAttr) {
                    cout << ',' << p.second;
                }
                cout << endl;
            }
            cout << endl;
        }
    }

    if (M.enable_ABM == "true") {
        cout << ',' << M.nI;
    }
}

// void Writer::writeMetaData(const Graph &M) {
// if (!dataFile.is_open()) {
// cerr << "ERRORF!" << endl;
// exit(EXIT_FAILURE);
// }
// dataFile << "network" << ',' << M.network << endl;
// dataFile << "dynamic" << ',' << M.dynamic << endl;
// dataFile << "graph attribute:" << endl;
// for (const auto &item : M.attr)
// dataFile << item.first << ',' << item.second << endl;
// dataFile << "node attribute:" << endl;
// for (const auto &item : M.V[0].furAttr)
// dataFile << item.first << endl;
// dataFile << "edge set:" << ',';
// int sum = 0;
// for (const auto &i : M.E)
// for (const auto &j : i)
// if (j.isConnected)
// ++sum;
// dataFile << sum / 2;
// dataFile << endl;
// for (const auto &item : M.E[0])
// dataFile << ',' << item.ID.second;
// dataFile << endl;
// for (const auto &item : M.E) {
// dataFile << item[0].ID.first << ',';
// for (const auto &p : item)
// dataFile << p.isConnected << ',';
// dataFile << endl;
// }
// dataFile << endl;
// }

// void Writer::writeTempData(const Graph &M) {
// if (!dataFile.is_open()) {
// cerr << "ERRORF!" << endl;
// exit(EXIT_FAILURE);
// }
// dataFile << "date" << M.date;
// for (const auto &item : M.V[0].curAttr)
// dataFile << ',' << item.first;
// auto sum = M.V[0].curAttr;
// for (auto &key : sum)
// key.second = 0;
// for (auto &key : sum) {
// for (const auto &item : M.V) {
// auto p = item.curAttr.find(key.first);
// assert(p != item.curAttr.end());
// key.second += p->second;
// }
// }
// for (const auto &key : sum) {
// dataFile << ',' << "sum of " << key.first << ',' << key.second;
// }
// dataFile << endl;

// for (const auto &item : M.V) {
// dataFile << item.ID;
// for (const auto &p : item.curAttr) {
// dataFile << ',' << p.second;
// }
// dataFile << endl;
// }
// dataFile << endl;
// }
